package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os/exec"
	"runtime"
	"strconv"
	"web-im/api"
	"web-im/asset"
	"web-im/data"
	"web-im/etc"
	"web-im/signature"
)

var addr   string
var status *session

type session struct {
	AppId 		int  	`json:"sdkAppID"`
	AccountType int 	`json:"accountType"`
	Admin       string	`json:"admin"`
	Account     string	`json:"identifier"`
	Sign     	string	`json:"userSig"`
}

func init() {
	flag.StringVar(&addr, "addr", ":9008", "server address")
	flag.Parse()
}

func main() {
	fs := asset.AssetFS{
		Asset:     data.Asset,
		AssetDir:  data.AssetDir,
		AssetInfo: data.AssetInfo,
		Prefix:    "dist",
	}

	http.Handle("/", http.FileServer(&fs))
	http.HandleFunc("/login", handleLogin)
	http.HandleFunc("/logout", handleLogout)
	http.HandleFunc("/success", handleSuccess)

	uri := fmt.Sprintf("http://127.0.0.1%s", addr)
	fmt.Println("http server: ", uri)

	if err := openBrowser(uri); err != nil {
		fmt.Println("open browser error:", err)
	}

	if err := http.ListenAndServe(addr, nil); err != nil {
		panic(err)
	}
}

func handleLogin(w http.ResponseWriter, r *http.Request) {
	var appID, accountType int
	var admin, account, key, sign string
	var err error

	if r.Method == http.MethodGet {
		if status == nil {
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
			return
		}
		body, _ := json.Marshal(status)
		w.Write(body)
		return
	}

	if r.Method != http.MethodPost {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	err = r.ParseForm()
	if err != nil {
		fmt.Println("error:", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	if v := r.Form.Get("appId"); len(v) <= 0 {
		fmt.Println("error:", fmt.Sprintf("appId is empty"))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	} else {
		appID, err = strconv.Atoi(r.Form.Get("appId"))
		if err != nil {
			fmt.Println("error:", err)
			http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
			return
		}
	}

	if v := r.Form.Get("accountType"); len(v) <= 0 {
		fmt.Println("error:", fmt.Sprintf("accountType is empty"))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	} else {
		accountType, err = strconv.Atoi(r.Form.Get("accountType"))
		if err != nil {
			fmt.Println("error:", err)
			http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
			return
		}
	}

	if v := r.Form.Get("admin"); len(v) <= 0 {
		fmt.Println("error:", fmt.Sprintf("admin is empty"))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	} else {
		admin = r.Form.Get("admin")
	}

	if v := r.Form.Get("account"); len(v) <= 0 {
		fmt.Println("error:", fmt.Sprintf("account is empty"))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	} else {
		account = r.Form.Get("account")
	}

	if v := r.Form.Get("key"); len(v) <= 0 {
		fmt.Println("error:", fmt.Sprintf("key is empty"))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	} else {
		key = r.Form.Get("key")
	}

	sign, err = signature.New(appID).WithAccountType(accountType).Generate(account, key)
	if err != nil {
		fmt.Println("error:", err)
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}

	status = &session{
		AppId: appID,
		AccountType: accountType,
		Admin: admin,
		Account: account,
		Sign: sign,
	}

	etc.AppID = appID
	etc.AccountType = accountType
	etc.Admin = admin
	etc.PrivateKey = key

	body, _ := json.Marshal(status)

	w.Write(body)
}

func handleLogout(w http.ResponseWriter, r *http.Request) {
	status = nil
	w.Write([]byte(""))
}

func handleSuccess(w http.ResponseWriter, r *http.Request) {
	if status != nil {
		_, err := api.SendMessage(status.Account, "Welcome to web-im")
		if err != nil {
			fmt.Println("error:", err)
		}
	}

	w.Write([]byte(""))
}

func openBrowser(url string) (err error) {
	switch runtime.GOOS {
	case "linux":
		return exec.Command("xdg-open", url).Start()
	case "windows":
		return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
	case "darwin":
		return exec.Command("open", url).Start()
	default:
		return fmt.Errorf("unsupported platform")
	}
}